# Copyright (c) Phigent Robotics. All rights reserved.

# 每个nuScenes序列大约包含40个关键帧. 
# 我们的训练流程首先采样序列，然后从第一个帧开始按顺序加载所采样序列中的帧
# 这会降低训练步骤之间的多样性，从而降低性能。
# 为了增加多样性，我们将每个训练序列均分为两半（约20个关键帧），并在训练过程中采样这些较短的序列。
# 在测试阶段，我们不进行这种分割。

# 序列分割策略
train_sequences_split_num = 4
test_sequences_split_num = 1

# By default, 3D detection datasets randomly choose another sample if there is
# no GT object in the current sample. This does not make sense when doing
# sequential sampling of frames, so we disable it.
# 数据增强控制
filter_empty_gt = False

# Long-Term Fusion Parameters
# 长期融合参数
do_history = False
history_cat_num = 4
history_cat_conv_out_channels = 160

_base_ = ['../_base_/datasets/nus-3d.py', '../_base_/default_runtime.py']


# BEV空间定义
roi_size = (102.4, 102.4) # BEV视角覆盖范围
bev_h = 128 # BEV特征图分辨率
bev_w = 128

# Global
# If point cloud range is changed, the models should also change their point
# cloud range accordingly
point_cloud_range = [-51.2, -51.2, -5.0, 51.2, 51.2, 3.0]
# For nuScenes we usually do 10-class detection
class_names = [
    'car', 'truck', 'construction_vehicle', 'bus', 'trailer', 'barrier',
    'motorcycle', 'bicycle', 'pedestrian', 'traffic_cone'
]

data_config = {
    'cams': [
        'CAM_FRONT_LEFT', 'CAM_FRONT', 'CAM_FRONT_RIGHT', 'CAM_BACK_LEFT',
        'CAM_BACK', 'CAM_BACK_RIGHT'
    ],
    'Ncams':
    6,
    'input_size': (256, 704),
    'src_size': (900, 1600),

    # Augmentation
    'resize': (-0.06, 0.11),
    'rot': (-5.4, 5.4),
    'flip': True,
    'crop_h': (0.0, 0.0),
    'resize_test': 0.00,
}

# Model
grid_config = {
    'x': [-51.2, 51.2, 0.8],
    'y': [-51.2, 51.2, 0.8],
    'z': [-5, 3, 8],
    'depth': [1.0, 60.0, 1.0],
}

voxel_size = [0.1, 0.1, 0.2]

numC_Trans = 80

embed_dims = 256
num_feat_levels = 1
norm_cfg = dict(type='BN2d')
num_queries = 100

num_points = 20 # 点云采样点数或线段表示点数
permute = True # 是否对数据进行置换处理
with_ego_as_agent = False # 是否将自身车辆视为代理

multi_adj_frame_id_cfg = (1, 1+1, 1)

model = dict(
    type='BEVDepth4DOCC_E2E',
    with_ego_status=True,
    align_after_view_transfromation=False,
    num_adj=len(range(*multi_adj_frame_id_cfg)),
    img_backbone=dict(
        pretrained='torchvision://resnet50',
        type='ResNet',
        depth=50,
        num_stages=4,
        out_indices=(2, 3),
        frozen_stages=-1,
        norm_cfg=dict(type='BN', requires_grad=True),
        norm_eval=False,
        with_cp=False,
        style='pytorch'),
    img_neck=dict(
        type='CustomFPN',
        in_channels=[1024, 2048],
        out_channels=512,
        num_outs=1,
        start_level=0,
        out_ids=[0]),
    img_view_transformer=dict(
        type='LSSViewTransformerBEVDepth',
        grid_config=grid_config,
        input_size=data_config['input_size'],
        in_channels=512,
        out_channels=numC_Trans,
        depthnet_cfg=dict(use_dcn=False, aspp_mid_channels=96),
        downsample=16),
    img_bev_encoder_backbone=dict(
        type='CustomResNet',
        numC_input=numC_Trans * (len(range(*multi_adj_frame_id_cfg))+1),
        num_channels=[numC_Trans * 2, numC_Trans * 4, numC_Trans * 8]),
    img_bev_encoder_neck=dict(
        type='FPN_LSS',
        in_channels=numC_Trans * 8 + numC_Trans * 2,
        out_channels=256),
    pre_process=dict(
        type='CustomResNet',
        numC_input=numC_Trans,
        num_layer=[2,],
        num_channels=[numC_Trans,],
        stride=[1,],
        backbone_output_ids=[0,]),
    occ_head=dict(
        type='BEVOCCHead2D',
        in_dim=256,
        out_dim=256,
        Dz=16,
        use_mask=True,
        num_classes=18,
        use_predicter=True,
        class_wise=False,
        loss_occ=dict(
            type='CrossEntropyLoss',
            use_sigmoid=False,
            ignore_index=255,
            loss_weight=1.0
        )
    ),
    planner_head=dict(
        type='NaivePlannerHead',
        with_ego_status=True,
        embed_dims=embed_dims
    )

)

# Data
dataset_type = 'NuScenesDatasetOccpancyPlan'
data_root = 'data/nuscenes/'
file_client_args = dict(backend='disk')

bda_aug_conf = dict(
    rot_lim=(-22.5, 22.5),
    scale_lim=(0.95, 1.05),
    flip_dx_ratio=0.5,
    flip_dy_ratio=0.5)

train_pipeline = [
    dict(
        type='PrepareImageInputs',
        is_train=True,
        data_config=data_config,
        sequential=True),
    dict(type='LoadOccGTFromFile'),

    dict(type='LoadAnnotations'),
    dict(
        type='BEVAug',
        bda_aug_conf=bda_aug_conf,
        classes=class_names),
    dict(
        type='LoadPointsFromFile',
        coord_type='LIDAR',
        load_dim=5,
        use_dim=5,
        file_client_args=file_client_args),
    dict(
        type='LoadVectorMap2',
        data_root = data_root,
        point_cloud_range =point_cloud_range,
        map_classes = ['divider', 'ped_crossing', 'boundary'],
        map_num_vec = 100,
        map_fixed_ptsnum_per_line = 20, # now only support fixed_pts > 0,
        map_eval_use_same_gt_sample_num_flag = True,
        map_num_classes = 3,
    ),   
    dict(type='PointToMultiViewDepth', downsample=1, grid_config=grid_config),
    dict(type='LoadGTPlaner'),

    dict(type='DefaultFormatBundle3D_Plan', class_names=class_names),
    dict(
        type='Collect3D_Plan', keys=['img_inputs', 
                                     'gt_depth', 
                                     'voxel_semantics',
                                     'mask_lidar',
                                     'mask_camera', 
                                     'gt_labels_3d',
                                     'can_bus_info',
                                     'gt_ego_lcf_feat',
                                     'gt_ego_fut_trajs',
                                     'gt_ego_his_trajs',
                                     'gt_ego_fut_cmd',
                                     'gt_ego_fut_masks',
                                     'map_gt_bboxes_3d'
                                    #  'gt_agent_fut_traj_mask',
                                    #  'gt_agent_fut_traj',
                                     ])
]

test_pipeline = [
    dict(
        type='PrepareImageInputs',
        is_train=False,
        data_config=data_config,
        sequential=True),
    dict(type='LoadAnnotations'),
    dict(
        type='BEVAug',
        bda_aug_conf=bda_aug_conf,
        classes=class_names),
    dict(
        type='LoadPointsFromFile',
        coord_type='LIDAR',
        load_dim=5,
        use_dim=5,
        file_client_args=file_client_args),
    dict(type='PointToMultiViewDepth', downsample=1, grid_config=grid_config),
            dict(
                type='LoadVectorMap',
                data_root = data_root,
                point_cloud_range =point_cloud_range,
                map_classes = ['divider', 'ped_crossing', 'boundary'],
                map_num_vec = 100,
                map_fixed_ptsnum_per_line = 20, # now only support fixed_pts > 0,
                map_eval_use_same_gt_sample_num_flag = True,
                map_num_classes = 3,
            ),  
    dict(type='LoadGTPlaner'),
    dict(type='LoadFutBoxInfo'),
    dict(
        type='MultiScaleFlipAug3D',
        img_scale=(1333, 800),
        pts_scale_ratio=1,
        flip=False,
        transforms=[
            dict(
                type='DefaultFormatBundle3D_Plan',class_names=class_names,with_label=False),
            dict(
                type='Collect3D_Plan', keys=['img_inputs', 
                                             'points',
                                            # 'gt_depth', 
                                            # 'voxel_semantics',
                                            # 'mask_lidar',
                                            # 'mask_camera', 
                                            # 'gt_labels_3d',
                                            'can_bus_info',
                                            'gt_ego_lcf_feat',
                                            'gt_ego_fut_trajs',
                                            'gt_ego_his_trajs',
                                            'gt_ego_fut_cmd',
                                            'gt_ego_fut_masks',
                                            'map_gt_bboxes_3d',
                                            'gt_fut_segmentations',
                                            'gt_fut_segmentations_plus'
                                            #  'gt_agent_fut_traj_mask',
                                            #  'gt_agent_fut_traj',
                                            ])
]
    )]
input_modality = dict(
    use_lidar=False,
    use_camera=True,
    use_radar=False,
    use_map=False,
    use_external=False)

share_data_config = dict(
    type=dataset_type,
    classes=class_names,
    modality=input_modality,
    img_info_prototype='bevdet4d',
    multi_adj_frame_id_cfg=multi_adj_frame_id_cfg,
    use_sequence_group_flag=True,
)

test_data_config = dict(
    pipeline=test_pipeline,
    load_fut_bbox_info=True,
    ann_file=data_root + 'bevdetplan-nuscenes_infos_val.pkl')

data = dict(
    samples_per_gpu=4,
    workers_per_gpu=4,
    train=dict(
        type='CBGSDataset',
        dataset=dict(
        data_root=data_root,
        ann_file=data_root + 'bevdetplan-nuscenes_infos_train.pkl',
        pipeline=train_pipeline,
        classes=class_names,
        test_mode=False,
        use_valid_flag=True,
        # we use box_type_3d='LiDAR' in kitti and nuscenes dataset
        # and box_type_3d='Depth' in sunrgbd and scannet dataset.
        box_type_3d='LiDAR')),
    val=test_data_config,
    test=test_data_config)

for key in ['val', 'test']:
    data[key].update(share_data_config)
data['train']['dataset'].update(share_data_config)

# Optimizer
optimizer = dict(type='AdamW', lr=2e-4, weight_decay=1e-2)
optimizer_config = dict(grad_clip=dict(max_norm=5, norm_type=2))
lr_config = dict(
    policy='step',
    warmup='linear',
    warmup_iters=200,
    warmup_ratio=0.001,
    step=[20,])
runner = dict(type='EpochBasedRunner', max_epochs=20)
find_unused_parameters = True
custom_hooks = [
    dict(
        type='MEGVIIEMAHook',
        init_updates=10560,
        priority='NORMAL',
    ),
    dict(
        type='SequentialControlHook',
        temporal_start_epoch=2,
    ),
]

# fp16 = dict(loss_scale='dynamic')
